package com.fileupload.server;

import com.fileupload.config.ServerConfig;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;

/**
 * FTP连接实现类
 * @author 小乙
 */
public class FtpConnection implements Connection {
    private static final Logger logger = LoggerFactory.getLogger(FtpConnection.class);
    
    private ServerConfig serverConfig;
    private FTPClient ftpClient;
    
    public FtpConnection(ServerConfig serverConfig) {
        this.serverConfig = serverConfig;
        this.ftpClient = new FTPClient();
        this.ftpClient.setControlEncoding("UTF-8");
    }
    
    @Override
    public boolean connect() throws IOException {
        try {
            String[] addrParts = serverConfig.getAddr().split(":");
            String host = addrParts[0];
            int port = addrParts.length > 1 ? Integer.parseInt(addrParts[1]) : 21;
            
            // 连接FTP服务器
            ftpClient.connect(host, port);
            
            // 检查连接是否成功
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                logger.error("FTP连接失败: 服务器返回码 {}", reply);
                ftpClient.disconnect();
                return false;
            }
            
            // 登录FTP服务器
            boolean loginSuccess = ftpClient.login(serverConfig.getUsername(), serverConfig.getPasswd());
            if (!loginSuccess) {
                logger.error("FTP登录失败: 用户名或密码错误");
                return false;
            }
            
            // 设置传输模式
            if ("passive".equalsIgnoreCase(serverConfig.getFtpMode())) {
                ftpClient.enterLocalPassiveMode();
            } else {
                ftpClient.enterLocalActiveMode();
            }
            
            // 设置文件类型为二进制
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            
            logger.info("FTP服务器连接成功: {}", serverConfig.getName());
            return true;
        } catch (IOException e) {
            logger.error("FTP连接异常: {}", e.getMessage());
            throw e;
        }
    }
    
    @Override
    public void disconnect() throws IOException {
        try {
            if (ftpClient != null && ftpClient.isConnected()) {
                ftpClient.logout();
                ftpClient.disconnect();
                logger.info("FTP服务器断开连接: {}", serverConfig.getName());
            }
        } catch (IOException e) {
            logger.error("FTP断开连接异常: {}", e.getMessage());
            throw e;
        }
    }
    
    @Override
    public boolean isConnected() {
        return ftpClient != null && ftpClient.isConnected();
    }
    
    @Override
    public boolean uploadFile(File file, String remotePath, String remoteFileName) throws IOException {
        if (!isConnected()) {
            logger.warn("FTP未连接，无法上传文件");
            return false;
        }
        
        try (FileInputStream fis = new FileInputStream(file)) {
            // 确保远程目录存在
            if (!remotePath.endsWith("/")) {
                remotePath = remotePath + "/";
            }
            String fullRemotePath = remotePath + remoteFileName;
            
            String remoteDir = remotePath;
            if (!directoryExists(remoteDir)) {
                createDirectory(remoteDir);
            }
            
            boolean success = ftpClient.storeFile(fullRemotePath, fis);
            
            if (success) {
                logger.info("文件上传成功: {} -> {}", file.getAbsolutePath(), fullRemotePath);
            } else {
                logger.error("文件上传失败: {} -> {}", file.getAbsolutePath(), fullRemotePath);
            }
            
            return success;
        } catch (IOException e) {
            logger.error("文件上传异常: {}", e.getMessage());
            throw e;
        }
    }
    
    @Override
    public boolean createDirectory(String directory) throws IOException {
        if (!isConnected()) {
            return false;
        }
        
        // 递归创建目录
        String[] dirs = directory.split("/");
        StringBuilder currentDir = new StringBuilder();
        
        for (String dir : dirs) {
            if (dir.isEmpty()) continue;
            
            currentDir.append("/").append(dir);
            String path = currentDir.toString();
            
            if (!ftpClient.changeWorkingDirectory(path)) {
                boolean created = ftpClient.makeDirectory(path);
                if (!created) {
                    logger.error("创建目录失败: {}", path);
                    return false;
                }
                if (!ftpClient.changeWorkingDirectory(path)) {
                    logger.error("切换目录失败: {}", path);
                    return false;
                }
            }
        }
        
        logger.info("目录创建成功: {}", directory);
        return true;
    }
    
    @Override
    public boolean directoryExists(String directory) throws IOException {
        if (!isConnected()) {
            return false;
        }
        
        String currentDir = ftpClient.printWorkingDirectory();
        boolean exists = ftpClient.changeWorkingDirectory(directory);
        
        // 恢复当前目录
        if (currentDir != null) {
            ftpClient.changeWorkingDirectory(currentDir);
        }
        
        return exists;
    }
    
    @Override
    public boolean writeTextFile(String remotePath, String content) throws IOException {
        if (!isConnected()) {
            return false;
        }
        
        try (ByteArrayInputStream bais = new ByteArrayInputStream(content.getBytes("UTF-8"))) {
            // 确保远程目录存在
            String remoteDir = remotePath.substring(0, remotePath.lastIndexOf('/'));
            if (!directoryExists(remoteDir)) {
                createDirectory(remoteDir);
            }
            
            boolean success = ftpClient.storeFile(remotePath, bais);
            
            if (success) {
                logger.info("文本文件写入成功: {}", remotePath);
            } else {
                logger.error("文本文件写入失败: {}", remotePath);
            }
            
            return success;
        } catch (IOException e) {
            logger.error("文本文件写入异常: {}", e.getMessage());
            throw e;
        }
    }
    
    @Override
    public boolean renameFile(String oldFilePath, String newFilePath) throws IOException {
        if (!isConnected()) {
            logger.warn("FTP未连接，无法重命名文件");
            return false;
        }
        
        try {
            boolean success = ftpClient.rename(oldFilePath, newFilePath);
            if (success) {
                logger.info("文件重命名成功: {} -> {}", oldFilePath, newFilePath);
            } else {
                logger.error("文件重命名失败: {} -> {}", oldFilePath, newFilePath);
            }
            return success;
        } catch (IOException e) {
            logger.error("文件重命名异常: {}", e.getMessage());
            throw e;
        }
    }
}